package com.fastwire.carriere.controller.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fastwire.carriere.common.Messages;
import com.fastwire.carriere.common.constant.HuaweiInventoryConstants;
import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.mapper.NENameMapper;
import com.fastwire.carriere.common.mapper.ReverseNameMapper;
import com.fastwire.carriere.common.mapper.TPNameMapper;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.StringUtil;
import com.fastwire.carriere.controller.FDFrController;
import com.fastwire.carriere.dao.CrossConnectDao;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.FDFRDao;
import com.fastwire.carriere.dao.NetworkInventoryDao;
import com.fastwire.carriere.dao.TrafficConditioningProfileDao;
import com.fastwire.carriere.hibernate.daoimpl.NetworkInventoryDaoImpl;
import com.fastwire.carriere.inventory.entity.CrossConnect;
import com.fastwire.carriere.inventory.entity.FDFr;
import com.fastwire.carriere.inventory.entity.NetworkElement;
import com.fastwire.carriere.inventory.entity.NetworkEntityUserSpecificInfo;
import com.fastwire.carriere.inventory.entity.TransmissionParameter;
import com.fastwire.carriere.inventory.vo.ConnectivityVo;
import com.fastwire.carriere.inventory.vo.FDFrVo;
import com.fastwire.carriere.rad.controller.RadProcessController;
import com.fastwire.carriere.rad.controller.RadProcessControllerImp;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;

public class FDFrControllerImpl implements FDFrController {

	/** The fdfr dao. */
	private final FDFRDao fdfrDao = DAOFactory.getInstance().getFdfrDao();

	/** The cc dao. */
	private final CrossConnectDao ccDao = DAOFactory.getInstance()
			.getCrossConnectDao();

	private final TrafficConditioningProfileDao tcfDao = DAOFactory
			.getInstance().getTrafficConditioningProfileDao();

	private final NetworkInventoryDao inventoryDao = new NetworkInventoryDaoImpl();

	/**
	 * Group fd frby slot and port.
	 * 
	 * @param neID
	 *            the ne id
	 * @return the hash multimap
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public HashMultimap<String, FDFrVo> groupFdFrbySlotAndPort(String neID)
			throws DAOException {

		List<String> neList = new ArrayList<String>();
		neList.add(neID);
		List<FDFr> fdfrList = DAOFactory.getInstance().getFdfrDao()
				.findFdFrbyNEName(neID);

		HashMultimap<String, FDFrVo> fdfrSlotMap = HashMultimap.create();

		for (FDFr fdfr : fdfrList) {

			FDFrVo fdFrVo = new FDFrVo(fdfr);

			String aendKey = TPNameMapper.getTPHashKey(fdfr.getAendTp()
					.getName());
			String zendKey = TPNameMapper.getTPHashKey(fdfr.getZendTp()
					.getName());

			if (!StringUtil.isEmptyString(aendKey)) {

				fdfrSlotMap.put(aendKey, fdFrVo);

			}

			if (!StringUtil.isEmptyString(zendKey)) {

				fdfrSlotMap.put(zendKey, fdFrVo);

			}

		}

		return fdfrSlotMap;

	}

	/**
	 * Gets the pMPFDFR grouphby ne.
	 * 
	 * @param neId
	 *            the ne id
	 * @param tpName
	 *            the tp name
	 * @return the pMPFDFR grouphby ne
	 * @throws DAOException
	 *             the dAO exception
	 * @throws ResourceException
	 */
	@Override
	public List<ConnectivityVo> getPMPFDFRGrouphbyNE(String neId, String tpName)
			throws DAOException, ResourceException {

		FDFRDao fdfrDao = DAOFactory.getInstance().getFdfrDao();

		List<FDFr> fdfrList = fdfrDao.findPMPFdFrbyNEName(neId);

		String slot = ReverseNameMapper.getSlot(tpName);
		String port = ReverseNameMapper.getPort(tpName);

		Pattern cmdPattern = Pattern.compile(".*/slot=" + slot + ".*/port="
				+ port + ".*CTP=.*");

		List<ConnectivityVo> connectivityVos = Lists.newArrayList();

		for (FDFr fdfr : fdfrList) {
			String aendTpString = fdfr.getAendTp().getName();

			Matcher matcher = cmdPattern.matcher(aendTpString);
			if (matcher.matches()) {

				List<FDFr> fdfrs = fdfrDao.findFdFrbyName(fdfr
						.getEmsNativeName());

				List<FDFr> newFdFrs = Lists.newArrayList();

				for (FDFr fdFr2 : fdfrs) {
					String aendTp = fdFr2.getAendTp().getName();
					String aendNeId = NENameMapper.getNEIdbyName(aendTp);
					if (neId.equals(aendNeId)) {
						newFdFrs.add(0, fdFr2);
					} else {
						newFdFrs.add(fdFr2);
					}
				}

				ConnectivityVo connectivityVo = stitchFDFrService(newFdFrs);

				if (connectivityVo != null) {
					connectivityVos.add(connectivityVo);
				}

			}
		}

		return connectivityVos;

	}

	/**
	 * Gets the tunnel nameby service name.
	 * 
	 * @param fdfrName
	 *            the fdfr name
	 * @return the tunnel nameby service name
	 * @throws DAOException
	 *             the dAO exception
	 * @throws ResourceException
	 */
	@Override
	public List<String> getTunnelNamebyServiceId(String serviceId)
			throws DAOException, ResourceException {

		List<FDFr> fdFrList = fdfrDao.findFdFrbyServiceId(serviceId);

		List<String> tunnelNameList = new ArrayList<String>();

		Pattern pattern = Pattern
				.compile(".*TUNNEL=(.*|.*|.*|.*|\\d+\\|\\|\\d+)");

		if (fdFrList == null || fdFrList.isEmpty()) {
			throw new ResourceException(Messages.getString(
					"message.fdfr.sidnotexistent.exception",
					new String[] { serviceId }));
		}
		//FDFR U2K NAME = MD=Huawei/U2000::ME=3145735::FDFR=PWE3=2|39|
		//To get a tunnel name from FDFR
		for (FDFr fdfr : fdFrList) {
			Set<TransmissionParameter> transParameters = fdfr.getZendTp()
					.getTransParameters();
			CommonLogger.debug(this, "Found a FDFR: "+ fdfr.getEmsNativeName());
			for (TransmissionParameter transParameter : transParameters) {
				//The BindingObject format  = MD=Huawei/U2000;ME=3145735;SNC=TUNNEL=1|1|173.254.9.4|173.9.179.151|772||1
				String tunnelName = transParameter
						.getParameter(HuaweiInventoryConstants.FDFR_BindingObject);
				
				if (!StringUtil.isEmptyString(tunnelName)) {
					CommonLogger.debug(this, "Found a svc param: "+ tunnelName);
					Matcher matcher = pattern.matcher(tunnelName);
					if (matcher.matches()
							& !tunnelNameList.contains(matcher.group(1))) {
						tunnelNameList.add(matcher.group(1));
					}
				}
			}
		}

		List<String> ccNameStrings = new ArrayList<String>();

		for (String tunnelID : tunnelNameList) {
			//Find crossconects by matching crossconnect (/FDFR's bindingobject) u2k name  
			List<CrossConnect> ccList = ccDao.getCrossConnectsbyServiceID(
					tunnelID, null);
			if (ccList != null && ccList.size() > 0)
				ccNameStrings.add(ccList.get(0).getEmsNativeName());

		}

		return ccNameStrings;
	}

	/**
	 * Stitch fd fr service.
	 * 
	 * @param fdfrList
	 *            the fdfr list
	 * @return the connectivity vo
	 * @throws DAOException
	 *             the dAO exception
	 * @throws ResourceException
	 */
	private ConnectivityVo stitchFDFrService(List<FDFr> fdfrList)
			throws DAOException, ResourceException {

		if (fdfrList.size() < 2) {
			return null;
		}
		ConnectivityVo connectivityVo = new ConnectivityVo();
		FDFr firstFdFr = fdfrList.get(0);
		FDFr lastFdFr = fdfrList.get(1);
		connectivityVo.setDirectionality(firstFdFr.getDirection());
		connectivityVo.setName(firstFdFr.getEmsNativeName());

		int bandwidth_first = getFDFrbandwidth(firstFdFr);

		int bandwidth_second = getFDFrbandwidth(lastFdFr);

		if (bandwidth_first > 0 && bandwidth_second > 0)

			connectivityVo.setBandwidth(String.valueOf(Math.min(
					bandwidth_first, bandwidth_second)));
		else if (bandwidth_first > 0) {
			connectivityVo.setBandwidth(String.valueOf(bandwidth_first));
		} else if (bandwidth_second > 0) {
			connectivityVo.setBandwidth(String.valueOf(bandwidth_second));
		}
		else // modified by Jun on 20120509
		{
		    connectivityVo.setBandwidth("0");
		}

		NetworkElement firstNE = NENameMapper.getNEbyU2kName(firstFdFr
				.getName());
		NetworkElement lastNE = NENameMapper.getNEbyU2kName(lastFdFr.getName());

		String aendTp = TPNameMapper.getReadableTpName(firstFdFr.getAendTp()
				.getName(), firstFdFr.getAendTp().getType(), firstNE);
		String zendTp = TPNameMapper.getReadableTpName(lastFdFr.getAendTp()
				.getName(), lastFdFr.getAendTp().getType(), lastNE);
		connectivityVo.setAendTp(aendTp);
		connectivityVo.setZendTp(zendTp);
		connectivityVo.setaEnd(firstNE, firstFdFr);
		connectivityVo.setzEnd(lastNE, lastFdFr);

		return connectivityVo;
	}

	/**
	 * Stitch fd fr service.
	 * 
	 * @param nativeEmsName
	 *            the native ems name
	 * @return the connectivity vo
	 * @throws ResourceException
	 *             the resource exception
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public ConnectivityVo stitchFDFrService(String nativeEmsName)
			throws ResourceException, DAOException {

		List<FDFr> fdfrList = fdfrDao.findFdFrbyEmsNativeName(nativeEmsName);

		if (fdfrList.size() != 2) {

			throw new ResourceException(Messages.getString(
					"message.fdfr.exception.incorrectsize",
					new String[] { String.valueOf(fdfrList.size()) }));

		}

		return stitchFDFrService(fdfrList);

	}

	//---------------------------------------------------------------------------------------------;
	// added by Jun on 20120509
	// add the RAD to the connectivity
	@Override
	public List<ConnectivityVo> stitchRad(ConnectivityVo connVo) throws ResourceException, DAOException
	{
        RadProcessController radCtrl = new RadProcessControllerImp();

	    return radCtrl.stitchRad2Service(connVo);
	}
	
	
	/**
	 * Gets the fd frsby ne.
	 * 
	 * @param neId
	 *            the ne id
	 * @return the fd frsby ne
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<FDFrVo> getFdFrsbyNE(String neId) throws DAOException {

		List<FDFr> fdfrList = fdfrDao.findFdFrbyNEName(neId);
		List<FDFrVo> fdFrVos = Lists.newArrayList();
		for (FDFr fdfr : fdfrList) {
			fdFrVos.add(new FDFrVo(fdfr));
		}

		return fdFrVos;

	}

	/**
	 * Gets the fd frby native ems name and ne id.
	 * 
	 * @param nativeEmsName
	 *            the native ems name
	 * @param neId
	 *            the ne id
	 * @return the fd frby native ems name and ne id
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public FDFrVo getFdFrbyNativeEmsNameAndNeId(String nativeEmsName,
			String neId) throws DAOException {
		FDFr fdfr = fdfrDao.findFdFrbyNENameAndEmsNativeName(nativeEmsName,
				neId);

		return new FDFrVo(fdfr);

	}

	/**
	 * Gets the fD frsby tunnel name.
	 * 
	 * @param tunnelName
	 *            the tunnel name
	 * @return the fD frsby tunnel name
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<FDFrVo> getFDFrsbyTunnelName(String tunnelName)
			throws DAOException {

		List<CrossConnect> ccList = ccDao.getCrossConnectsbyName(tunnelName);
		List<String> tunnelNameList = new ArrayList<String>();
		Pattern pattern = Pattern.compile(".*(TUNNEL=.*)\\|\\|.*");

		for (CrossConnect cc : ccList) {
			String ccname = cc.getName();
			Matcher matcher = pattern.matcher(ccname);
			if (matcher.matches()) {
				String tunnel = matcher.group(1);
				CommonLogger.info(this, "tunnel Name is " + tunnel + " end");
				if (!StringUtil.isEmptyString(tunnel)) {
					tunnelNameList.add(tunnel);
				}
			}

		}
		List<FDFr> fdfrList = Lists.newArrayList();

		for (String ccName : tunnelNameList) {

			fdfrList.addAll(fdfrDao.findFdFrbyTunnelName(ccName));

		}
		List<FDFrVo> fdFrVos = Lists.newArrayList();
		for (FDFr fdfr : fdfrList) {
			fdFrVos.add(new FDFrVo(fdfr));
		}

		return fdFrVos;
	}

	/**
	 * Search fd fr.
	 * 
	 * @param fdFrVo
	 *            the fd fr vo
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<String> searchFDFr(FDFrVo fdFrVo) throws DAOException {

		return fdfrDao.getFDFrsbyVo(fdFrVo);

	}

	@Override
	public int getFDFrbandwidth(FDFr fdfr) throws DAOException,
			ResourceException {
		int bandwidth = 0;
		/*
		 * String tmfValue = fdfr.getAendTp().getIngressTmdRef();
		 * 
		 * if (!StringUtil.isEmptyString(tmfValue)) { TrafficConditioningProfile
		 * tcf = tcfDao .getTrafficConditioningProfilesbyName(tmfValue);
		 * bandwidth = tcf.getBandwidth();
		 * 
		 * }
		 * 
		 * if (bandwidth > 0 && HuaweiInventoryConstants.BANDWIDTH_CIR_MAP
		 * .containsKey(bandwidth)) { bandwidth =
		 * HuaweiInventoryConstants.BANDWIDTH_CIR_MAP .get(bandwidth); }
		 * 
		 * if (bandwidth == 0) {
		 */
		List<String> tunnelList = getTunnelNamebyServiceId(fdfr
				.getEmsNativeName());
		bandwidth = new CrossConnectControllerImpl()
				.getBandwidthbyTunnelNameList(tunnelList);
		// }

		return bandwidth;
	}

	@Override
	public void updateFDFr(FDFrVo fdFrVo) throws DAOException {

		NetworkEntityUserSpecificInfo neUserSpecificInfo = inventoryDao
				.getNetworkEntityUserSpecificInfobyNameAndType(
						fdFrVo.getNativeEmsName(), FDFr.class.getSimpleName());

		if (neUserSpecificInfo == null) {
			neUserSpecificInfo = new NetworkEntityUserSpecificInfo();
			neUserSpecificInfo.setName(fdFrVo.getNativeEmsName());
			neUserSpecificInfo.setType(FDFr.class.getSimpleName());

		}

		neUserSpecificInfo.setRemark(fdFrVo.getRemarks());

		inventoryDao
				.saveOrUpdateNetworkEntityUserSpecificInfo(neUserSpecificInfo);

	}
}
